鼠标获取并删除Nape刚体的方法
删除刚体并不是什么复杂的技巧,但是仅仅只是这个简单的功能也可以做出像Totem destroyer这样优秀的Flash游戏(游戏截图如下)。你有没有像我一样,试图在Nape API文档里找到Space.destroy类似的函数?那是Box2D里的做法,今天我们就来学习一下,如何在Nape空间里删除一个刚体。
Nape与Box2D不同,Space里面没有像b2World.destroy()这样的方法来删除刚体。Nape类库里有nape.phys.BodyList类,Space中的所有刚体都保存在BodyList列表中,Body刚体和BodyList的关系就像是Flash里显示对象和显示列表一样。所以要在Nape中删除某个刚体,用BodyList.remove()方法把它从列表中移除即可。
具体的讲,Space中有一个BodyList类型的bodies属性,调用space.bodies.remove()方法,即可删除指定的刚体,具体如下:
//napeWorld是Space对象,bb是要删除的刚体 napeWorld.bodies.remove(bb);
知道了怎么删除Nape刚体之后,我们还要了解一件事情。Totem destroyer游戏中删除的是鼠标点击的刚体,那怎么获取鼠标点击的刚体呢?很简单,至少比Box2D的方法简单。
Space类中有一个bodiesUnderPoint()方法,看名字应该能猜出它的作用,获取某个点下面的刚体。是的,我们只要把鼠标的坐标点传入到bodiesUnderPoint()方法中,它就可以返回一个包含鼠标坐标下面所有刚体的一个BodyList对象,然后我们在用BodyList.foreach()方法遍历这些刚体,然后逐个删掉。foreach()的参数是一个函数,这个函数必须有一个Body类型的参数。下面是具体的代码:
//获取鼠标下方的body刚体 var bodiesList:BodyList = napeWorld.bodiesUnderPoint(mp); //遍历每个刚体 bodiesList.foreach( function( bb:Body):void{ if(bb.isDynamic()){ //如果刚体是非静止的,则删除刚体 napeWorld.bodies.remove(bb); } } );
好了,基本都讲完了,下面我们来看看用Nape实现的Totem destroyer游戏模型吧!
[swfobject]728[/swfobject]
是不是一模一样?源代码和注释如下:
package { import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import nape.phys.BodyList; import nape.constraint.PivotJoint; import nape.geom.Vec2; import nape.phys.Body; import nape.phys.BodyType; [SWF(frameRate="60",width=550,height=400,backgroundColor="0xCCCCCC")] public class T8_GetAndRemoveBody extends AbstractNapeTest { private var hand:PivotJoint; public function T8_GetAndRemoveBody() { super(); createWall(); createBodies(); //添加上方的按钮 var ui:UISetting = new UISetting(this, function (e:Event):void { //按钮点击事件处理函数 napeWorld.bodies.clear(); createWall(); createBodies(); }); } private function createBodies():void { //创建多个刚体,按照游戏中的样式摆放 createBox(275,335,30,30,BodyType.DYNAMIC); createBox(365,335,30,30,BodyType.DYNAMIC); createBox(320,305,120,30,BodyType.DYNAMIC); createBox(320,275,60,30,BodyType.DYNAMIC); createBox(305,245,90,30,BodyType.DYNAMIC); createBox(320,200,120,60,BodyType.DYNAMIC); } override protected function mouseEventHanlder(event:MouseEvent):void { if (event.type == MouseEvent.MOUSE_DOWN) { //获取鼠标位置向量 var mp:Vec2=new Vec2(mouseX,mouseY); //获取鼠标下方的body刚体 var bodiesList:BodyList = napeWorld.bodiesUnderPoint(mp); //遍历每个刚体 bodiesList.foreach( function( bb:Body):void{ if(bb.isDynamic()){ //如果刚体是非静止的,则删除刚体 napeWorld.bodies.remove(bb); } } ); } } } } import com.bit101.components.PushButton; import flash.display.DisplayObjectContainer; class UISetting{ public function UISetting(container:DisplayObjectContainer,handler:Function):void{ var btn:PushButton=new PushButton(container,300,10,"ReStart",handler); } }
对了,后面的教程中,我们还会重复的创建Nape世界、刚体、设置刚体的属性等等,为了避免重复复制粘贴代码,我把这些动作封装到了AbstractNapeTest.as类中,本例以及后面的教程,只要继承这个类,就可以轻松的创建Nape应用了。
完整的AbstractNapeTest.as类代码如下:
package { import flash.display.Graphics; import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.geom.Point; import nape.constraint.PivotJoint; import nape.geom.Vec2; import nape.phys.Body; import nape.phys.BodyType; import nape.phys.Material; import nape.shape.Circle; import nape.shape.Polygon; import nape.space.Space; import nape.util.BitmapDebug; [SWF( width="550", height="400", frameRate="60")] public class AbstractNapeTest extends Sprite { protected var napeWorld:Space; protected var debug:BitmapDebug; protected var isCtrlDown:Boolean; protected var isShiftDown:Boolean; protected var mouseJoint:PivotJoint; public function AbstractNapeTest() { //1.创建Nape空间,重力,调试视图 createNapeWorld(); //2.添加事件 setUpEvents(); //添加FPS监视器 addChild(new Stats()); } //创房Nape世界 protected function createNapeWorld():void { //定义Nape世界的重力 var gravity:Vec2 = new Vec2( 0, 600 ); napeWorld =new Space( gravity ); //添加Nape调试试图 debug= new BitmapDebug(550, 400, 0xD6D6D6); addChild(debug.display); } //添加事件侦听 protected function setUpEvents():void { //侦听帧更新事件 stage.addEventListener(Event.ENTER_FRAME, loop); //add listener to MouseEvent,like mouseDown or MouseUp stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseEventHanlder); stage.addEventListener(MouseEvent.MOUSE_UP, mouseEventHanlder); //侦听键盘事件 stage.addEventListener(KeyboardEvent.KEY_DOWN, keyBoardEventHanlder); stage.addEventListener(KeyboardEvent.KEY_UP, keyBoardEventHanlder); } protected function keyBoardEventHanlder(event:KeyboardEvent):void { //键盘事件处理函数 //在键盘按下时,记录Ctrl和Shift键的状态 isCtrlDown=event.ctrlKey; isShiftDown=event.shiftKey; } protected function mouseEventHanlder(event:MouseEvent):void { //鼠标事件处理函数 } protected function loop(event:Event):void { //更新Nape世界 napeWorld.step(1/60); debug.clear(); debug.draw(napeWorld); debug.flush(); } //创建矩形刚体,之前我们都已经讲过 protected function createBox(posX:Number, posY:Number, w:Number, h:Number, type:BodyType):void{ var box:Body = new Body(type, new Vec2(posX, posY)); var boxShape:Polygon=new Polygon(Polygon.box(w,h), Material.glass()); box.shapes.push(boxShape); box.space= napeWorld; } //创建指定边数的规则多边形刚体 protected function createRegular(posX:Number, posY:Number, r:Number, rotation:Number, edgeCount:int, type:BodyType):void{ var regular:Body = new Body(type, new Vec2(posX, posY)); //通过Polygon预定义的regular方法绘制规则的边数位edgeCount的多边形刚体 var regularShape:Polygon=new Polygon(Polygon.regular(r*2,r*2,edgeCount), Material.glass()); regularShape.rotate(rotation); regular.shapes.push(regularShape); regular.space= napeWorld; } //创建圆形刚体 protected function createCircle(posX:Number, posY:Number, radius:int, type:BodyType):void { var circle:Body=new Body(type, new Vec2(posX, posY)); var shape:Circle=new Circle(radius,null,Material.glass()); circle.shapes.push(shape); circle.space=napeWorld; } //绘制包围的静态刚体 protected function createWall():void{ createBox(stage.stageWidth/2, 0, stage.stageWidth, 10, BodyType.STATIC); createBox(stage.stageWidth/2, stage.stageHeight, stage.stageWidth, 10, BodyType.STATIC); createBox(0, stage.stageHeight/2, 10, stage.stageHeight, BodyType.STATIC); createBox(stage.stageWidth, stage.stageHeight/2, 10,stage.stageWidth, BodyType.STATIC); } } }
好了,23:14了,不早了,我睡觉了。
对了,源文件下载地址在这里!
联系作者
又是一篇给力的文章!谢谢分享:)
这么晚了,还来支持我的教程,感动啊!!
干嘛不写一个EasyNape呀
从早上看到现在,吧拉登大叔的BOX2D全看完,虽然没有全部自己写一遍,不过也体会不浅,
有了这些做个简单的物理游戏足够了,
希望拉登继续教程。
另外贴图能否平滑? 矢量效果倒是还可以,位图就抖 锯齿的厉害!
谢谢,我会继续努力的!!关于锯齿的问题,应该是Flash Player渲染本身的问题,跟Box2D没有太大关系,你可以试着设置stage.quality = StageQuality.HIGH;看看效果如何。
工作之后很久没来看了。突然多了几篇,赞一个~
老板。看完啦!更新更新!!!!
最近好忙啊!!周末吧!一定更新!
没学过物理引擎,最近刚好要做个CutRope,刚好可以用上nape,多谢教程
请问下我的body贴图了,好像 napeWorld.bodies.remove(bb);移除不了,是不是还有什么没有删掉呢,谢谢